#include "main.h"
#include "inc/hw_adc.h"
#include "driverlib/adc.h"
#include "inc/hw_timer.h"
#include "driverlib/timer.h"

#include "inc/hw_udma.h"
#include "driverlib/udma.h"

#ifdef DEBUG
void __error(char*file, int line)
{
    
}
#endif

void adc_int_handler();

/*
AIN0 6 PE3 I Analog Analog-to-digital converter input 0.
AIN1 7 PE2 I Analog Analog-to-digital converter input 1.
AIN2 8 PE1 I Analog Analog-to-digital converter input 2.
AIN3 9 PE0 I Analog Analog-to-digital converter input 3.
AIN4 64 PD3 I Analog Analog-to-digital converter input 4.
AIN5 63 PD2 I Analog Analog-to-digital converter input 5.
AIN6 62 PD1 I Analog Analog-to-digital converter input 6.
AIN7 61 PD0 I Analog Analog-to-digital converter input 7.
AIN8 60 PE5 I Analog Analog-to-digital converter input 8
*/
void init_adc()
{

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //RCC enable

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    // GPIOPinConfigure();
    // GPIOPinConfigure(GPIO_PF2_M1PWM6);
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3 | GPIO_PIN_2); // DIR ASFER

    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0); // ADC_TRIGGER_PROCESSOR
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0);   // first sample
    //  ADC_CTL_IE | ADC_CTL_END | ADC_CTL_CH0);
    // ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1);      //ADC_CTL_TS                                   // next sample
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1  | ADC_CTL_END | ADC_CTL_IE); // next sample

    // ADCHardwareOversampleConfigure(ADC0_BASE, 4); // x4 ADCSAC
    ADCIntRegister(ADC0_BASE, 0, adc_int_handler);
    ADCIntEnable(ADC0_BASE, 0);      // ADCIM
    ADCSequenceEnable(ADC0_BASE, 0); //ADCACTSS

    // ADC_IM_DMAMASK0
    uDMAChannelEnable(UDMA_PRI_SELECT | UDMA_CHANNEL_ADC0);
    // ADCProcessorTrigger(ADC0_BASE, 0);
}

// float vch[2], temprature;
// float dt;

int loadVal = 80 - 1, prescaleVal = 2-1;//80 - 1; // /8=1MHz 
void timerA0_int_handler();

void init_timer()
{
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    SysCtlDelay(3);
    TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC);

    TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
    TimerControlStall(TIMER0_BASE, TIMER_A, true);
    TimerLoadSet(TIMER0_BASE, TIMER_A, loadVal);
    TimerPrescaleSet(TIMER0_BASE, TIMER_A, prescaleVal);

    TimerIntRegister(TIMER0_BASE, TIMER_A, timerA0_int_handler);
    // TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    TimerEnable(TIMER0_BASE, TIMER_A);
}

void timerA0_int_handler()
{
    int s = TimerIntStatus(TIMER0_BASE, true);
    TimerIntClear(TIMER0_BASE, s);
    static float t0 = 0;
    float t = millisf();
    // dt = t - t0;
    t0 = t;
}

#define ADC_SEQ (ADC_O_SSMUX0)
#define ADC_SEQ_STEP (ADC_O_SSMUX1 - ADC_O_SSMUX0)
#define ADC_SSFIFO (ADC_O_SSFIFO0 - ADC_O_SSMUX0)
#define adc_buf_len 1//1024
static uint16_t adc_values_buffs[2][adc_buf_len];
const int *adc_fifo = ADC0_BASE + ADC_SEQ + (ADC_SEQ_STEP * 0) + ADC_SSFIFO;
void init_adc_dma()
{
    uDMAChannelAssign(UDMA_CH14_ADC0_0); //UDMA_CH9_UART0TX

    //    uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0TX,
    //                                UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
    //                                    UDMA_ATTR_HIGH_PRIORITY |
    //                                    UDMA_ATTR_REQMASK);
    uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC0, UDMA_ATTR_USEBURST); //UDMA_ATTR_HIGH_PRIORITY
    uDMAChannelControlSet(UDMA_PRI_SELECT | UDMA_CHANNEL_ADC0,
                          UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_2);
    uDMAChannelControlSet(UDMA_ALT_SELECT | UDMA_CHANNEL_ADC0,
                          UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_2);

    uDMAChannelTransferSet(UDMA_PRI_SELECT | UDMA_CHANNEL_ADC0, UDMA_MODE_PINGPONG,
                           adc_fifo, adc_values_buffs[0], adc_buf_len);
    uDMAChannelTransferSet(UDMA_ALT_SELECT | UDMA_CHANNEL_ADC0, UDMA_MODE_PINGPONG,
                           adc_fifo, adc_values_buffs[1], adc_buf_len);
    uDMAChannelEnable(UDMA_CHANNEL_ADC0);

    //enable after finished
}

// float tping, tping0, tpong, tpong0;
// int report_adc1()
// {
//     // static int c=0;
//     // c++;
//     // if(c>30)
//     // {
//     //     TimerIntDisable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
//     // }
//     li_outf("ping=%.1f\n", tping);
//     return 0;
// }

// int report_adc2()
// {
//     // static int c=0;
//     // c++;
//     // if(c>30)
//     // {
//     //     TimerIntDisable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
//     // }
//     li_outf("\tpong=%.1f\n", tpong);
//     return 0;
// }

void adc_int_handler()
{
    int s = ADCIntStatus(ADC0_BASE, 0, true);
    ADCIntClear(ADC0_BASE, 0);

    int mode = uDMAChannelModeGet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT);
    // bool isRun = uDMAChannelIsEnabled();
    if (mode == UDMA_MODE_STOP)
    {
        //do with the data in adc_values_buffs[0]
        // float t = millisf();
        // tping = t - tping0;
        // tping0 = t;
        uDMAChannelTransferSet(UDMA_PRI_SELECT | UDMA_CHANNEL_ADC0, UDMA_MODE_PINGPONG,
                               adc_fifo, adc_values_buffs[0], adc_buf_len);
        // addTask(report_adc1);
    }
    mode = uDMAChannelModeGet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT);
    // isRun = uDMAChannelIsEnabled(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT);

    if (mode == UDMA_MODE_STOP)
    {
        //do with the data in adc_values_buffs[0]
        // float t = millisf();
        // tpong = t - tpong0;
        // tpong0 = t;

        uDMAChannelTransferSet(UDMA_ALT_SELECT | UDMA_CHANNEL_ADC0, UDMA_MODE_PINGPONG,
                               adc_fifo, adc_values_buffs[1], adc_buf_len);
        // uDMAChannelEnable(UDMA_ALT_SELECT | UDMA_CHANNEL_ADC0);
        // addTask(report_adc2);
    }

    // int vchi[3];
    // ADCSequenceDataGet(ADC0_BASE, 0, vchi);
    // int i;
    // for (i = 0; i < 2; i++)
    //     vch[i] = vchi[i] * 3.3f / 0xfff;

    // temprature = 147.5f - ((75.0f * 3.3f * vchi[2]) / 4096.0f);
    // addTask(report_adc);
    // TEMP = 147.5 - ((75 * 3.3 × ADCCODE) / 4096)
}
